using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace OpenTap.Plugins.PluginDevelopment.Advanced_Examples
{
// This example shows how a 'virtual' property can be attached to
// any type. It supports serialization and showing it in a user interface
// However, direct references to it is more complicated and requires
// a reference to the DLL that defines. Additionally, the attached property
// can be made internal, further restricting access to it.
// This can be used as a useful way of limiting how it is being used.
//
// This requires the creation of a new ITypeDataProvider. Be careful when creating a TypeDataProvider
// it is easy to 'brick' your installation if it throws exceptions or make it slow if your TypeDataProvider
// is not optimized and does unnecessary work.
// In this example, let's add a unique identifier to all instruments.
// In the GUI there will be a Instrument ID field for all instruments.
// In XML this will look like adwadwa
public class InstrumentIDTypeDataProvider : IStackedTypeDataProvider
{
// This needs to be enabled from the example component settings.
internal static bool Enabled;
public ITypeData GetTypeData(string identifier, TypeDataProviderStack stack)
{
if (!Enabled) return null;
if (identifier.StartsWith(InstrumentIDTypeData.pre))
{
var inner = stack.GetTypeData(identifier.Substring(InstrumentIDTypeData.pre.Length));
return InstrumentIDTypeData.FromInnerType(inner);
}
return null;
}
public ITypeData GetTypeData(object obj, TypeDataProviderStack stack)
{
if (!Enabled) return null;
if (obj is IInstrument)
{
var inner = stack.GetTypeData(obj);
return InstrumentIDTypeData.FromInnerType(inner);
}
return null;
}
// Determined by calling PrintTypeDataProviders.
public double Priority => 2;
// uncomment these to see which type data providers exist
//public InstrumentIDTypeDataProvider()
//{
// if (printed) return;
// printed = true; // avoid recursive loop
// PrintTypeDataProviders();
//}
//static bool printed = false;
// To get an overview of the existing type data provider, we recommend calling this:
// This will help figure out which Priority we should choose.
static void PrintTypeDataProviders()
{
TraceSource log = Log.CreateSource("TypeData");
var items = TypeData.GetDerivedTypes()
.Where(x => x.CanCreateInstance)
.Select(x => x.CreateInstance())
.OfType()
.ToArray();
foreach (var item in items)
{
log.Info("{0} : {1}", item, item.Priority);
}
}
}
///
/// Helper class for getting / setting the instrument ID
///
public class InstrumentIDProperty
{
/// Gets the current ID of the instrument.
public static string GetValue(IInstrument instrument)
{
return InstrumentIDTypeData.InstrumentIdMember.GetValue(instrument) as string;
}
/// Sets the current ID of the instrument.
public static void SetValue(IInstrument instrument, string id)
{
InstrumentIDTypeData.InstrumentIdMember.SetValue(instrument, id);
}
}
///
/// This is the extension to the existing instrument type
///
class InstrumentIDTypeData : ITypeData
{
internal const string pre = "InstID:";
readonly ITypeData innerType;
///
/// It is very important that the type provider can resolve types very fast, therefore we store the type in this cache.
///
static readonly ConditionalWeakTable cache =
new ConditionalWeakTable();
public static ITypeData FromInnerType(ITypeData innerType)
{
return cache.GetValue(innerType, t => new InstrumentIDTypeData(t));
}
InstrumentIDTypeData(ITypeData innerType)
{
this.innerType = innerType;
}
/// We only need to define the ID member once. So here it is stored as a static value.
/// This can also help improve performance.
public static readonly InstrumentIDMemberData InstrumentIdMember =
new InstrumentIDMemberData(TypeData.FromType(typeof(string)), "Instrument.ID", null,
new DisplayAttribute("Instrument ID"));
public IEnumerable